package cjwt

import (
	"gitee.com/theegg/go-brick/app/service/app"
	"github.com/dgrijalva/jwt-go"
	"time"
)

// Token数据
type Claims struct {
	UserId int64 `json:"userid"`
	jwt.StandardClaims
}

// Token容器
type TokenContainer struct {
	key        string
	issuer     string
	expireTime time.Duration
	region     string
	token      string
}

// @description new 一个token容器
func NewTokenContainer(region string) *TokenContainer {
	tc := &TokenContainer{region: region}

	jwtConfig, errJwtConfig := app.Config.GetJwtConfig(region)
	if errJwtConfig != nil {
		panic(errJwtConfig.Error())
	}

	tc.key = jwtConfig.TokenKey
	tc.issuer = jwtConfig.TokenIssuer
	tc.expireTime = time.Hour * time.Duration(jwtConfig.TokenExpireHour)
	return tc
}

func (tc TokenContainer) Key() string {
	return tc.key
}

func (tc TokenContainer) Region() string {
	return tc.region
}

func (tc TokenContainer) Token() string {
	return tc.token
}

func (tc TokenContainer) ExpireTime() time.Duration {
	return tc.expireTime
}

func (tc TokenContainer) Issuer() string {
	return tc.issuer
}

// 获取域内配置
func (tc TokenContainer) GetRegionConfig() *app.JwtConfig {
	config, err := app.Config.GetJwtConfig(tc.region)
	if err != nil {
		panic("对不起, 无效的jwt域!")
	}
	return config
}

// 根据用户ID产生token
func (tc *TokenContainer) GenToken(userId int64) (string, error) {
	expireTime := time.Now().Add(time.Duration(tc.ExpireTime()) * time.Hour)
	claims := Claims{
		UserId: userId,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    tc.Issuer(),
		},
	}

	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString([]byte(tc.Key()))
	if err != nil {
		return "", err
	}

	tc.token = token

	return tc.Token(), err
}

// 解析
func (tc *TokenContainer) ParseToken(token string) (*Claims, error) {

	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(tc.Key()), nil
	})

	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil
		}
	}

	return nil, err

}
